package com.gemini.utis;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 处理反射的工具类
 */
public class ReflectUtil {

    //字段缓存
    public static Cache<Class<?>, Field[]> FIELDS_CACHE = Caffeine.newBuilder().expireAfterAccess(3, TimeUnit.MINUTES).maximumSize(10).build();


    /**
     * 反射获取对象的所有字段
     *
     * @param obj          目标对象
     * @param incloudSuper 是否包含父类字段
     * @return 字段集合（去重）
     */
    public static Field[] getAllFields(Object obj, boolean incloudSuper) {
        Class<?> clazz = obj.getClass();
        if (!incloudSuper) {
            return clazz.getDeclaredFields();
        }
        Field[] result = FIELDS_CACHE.get(clazz, ReflectUtil::getFields);

        return result;
    }


    private static Field[] getFields(Class<?> clazz) {

        Field[] fields = clazz.getDeclaredFields();
        List<Field> result = new ArrayList<>(Arrays.asList(fields));

        //遍历获取父类
        Class<?> superclass = clazz.getSuperclass();
        while (superclass != null) {
            Field[] declaredFields = superclass.getDeclaredFields();
            result.addAll(Arrays.asList(declaredFields));
            superclass = superclass.getSuperclass();
        }
        Field[] r = result.toArray(new Field[]{});
        return r;
    }


    /**
     * 反射获取对象的所有字段（包含父类）
     *
     * @param obj 目标对象
     * @return 字段集合
     */
    public static Field[] getAllFields(Object obj) {
        return getAllFields(obj, true);
    }


}
